﻿using MiniFox.Components;
using MiniFox.Data.EntityFramework;
using MiniFox.Platform.File.Models;
using MiniFox.Platform.File.Providers;
using MiniFox.Utility;
using System.Linq.Expressions;

namespace Platform.Data
{
    /// <summary>
    /// 
    /// </summary>
    [AutoResolve]
    public class GeneraicFolderProvider : EntityDataProvider<PlatformDbContext>, IFolderProvider
    {
        private Expression<Func<Folder, FolderObject>> CreateMapping()
        {
            Expression<Func<Folder, FolderObject>> mappingToVo = (folder) => new FolderObject
            {
                FolderId = folder.FolderId,
                FolderName = folder.FolderName,
                Group = folder.Group,
                Path = folder.Path,
                SuperId = folder.SuperId,
                Ordinal = folder.Ordinal,
                CreateTime = folder.CreateTime,
                UpdateTime = folder.UpdateTime,
                Files = (from f in this.CurrentDbContext.File
                         where f.Group == folder.Group && f.Path == folder.Path
                         select new FileData
                         {
                             FileId = f.FileId,
                             FileName = f.FileName,
                             ContentType = f.MimeType,
                             ContentLength = f.ContentLength,
                             Group = f.Group,
                             Path = f.Path,
                             CreateTime = f.CreateTime,
                             UpdateTime = f.UpdateTime
                         }).ToArray()
            };
            return mappingToVo;
        }
        //private void CopyRecursion(ITreeNode treeNode, Folder superFolder, List<BatchOperationItem> batchOperationItems)
        //{
        //    TreeNode<FolderObject> node = treeNode as TreeNode<FolderObject>;

        //    var newFolder = new Folder();
        //    newFolder.FolderId = SequenceGUID.NewGUID();
        //    newFolder.SuperId = superFolder.FolderId;
        //    newFolder.FolderName = node.Data.FolderName;
        //    newFolder.Group = node.Data.Group;
        //    newFolder.CreateTime = node.Data.CreateTime;
        //    newFolder.UpdateTime = node.Data.UpdateTime;
        //    newFolder.Path = $"{superFolder.Path}{newFolder.FolderName}/";
        //    newFolder.Ordinal = node.Data.Ordinal;

        //    batchOperationItems.Add(new BatchOperationItem { Entity = newFolder, State = Microsoft.EntityFrameworkCore.EntityState.Added });

        //    foreach (var childNode in treeNode.Children)
        //    {
        //        CopyRecursion(childNode, newFolder, batchOperationItems);
        //    }
        //    //foreach(var file in node.Data.Files)
        //    //{

        //    //}
        //}

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="group"></param>
        ///// <param name="newFolderId"></param>
        ///// <param name="folderId"></param>
        ///// <param name="superPath"></param>
        ///// <returns></returns>
        //public bool Copy(string group, string newFolderId, string folderId, string superPath)
        //{
        //    var targetSuper = this.CurrentDbContext.Folder.SingleOrDefault(f => f.Group == group && f.Path == superPath);

        //    var oldFolder = this.CurrentDbContext.Folder.SingleOrDefault(f => f.FolderId == folderId);

        //    var oldPath = oldFolder.Path;
        //    var newPath = $"{superPath}{oldFolder.FolderName}/";

        //    var newFolder = new Folder();
        //    newFolder.FolderId = newFolderId;
        //    newFolder.FolderName = oldFolder.FolderName;
        //    newFolder.Group = oldFolder.Group;
        //    newFolder.SuperId = targetSuper.FolderId;
        //    newFolder.Path = newPath;
        //    newFolder.CreateTime = DateTime.Now;
        //    newFolder.UpdateTime = DateTime.Now;
        //    newFolder.Ordinal = oldFolder.Ordinal;

        //    List<BatchOperationItem> list = [];
        //    list.Add(new BatchOperationItem
        //    {
        //        Entity = newFolder,
        //        State = Microsoft.EntityFrameworkCore.EntityState.Modified
        //    });

        //    var children = this.CurrentDbContext.Folder.Where(f => f.Group == group && f.Path != oldPath && f.Path.StartsWith(oldPath)).ToArray();
        //    foreach (var oldItem in children)
        //    {
        //        var newItem = new Folder();
        //        newItem.FolderId = SequenceGUID.NewGUID();
        //        newItem.FolderName = oldItem.FolderName;
        //        newItem.Group = oldItem.Group;
        //        newItem.SuperId = oldItem.FolderId;
        //        newItem.Path = oldItem.Path.Replace(oldPath, newPath);
        //        newItem.CreateTime = DateTime.Now;
        //        newItem.UpdateTime = DateTime.Now;
        //        newItem.Ordinal = oldItem.Ordinal;

        //        list.Add(new BatchOperationItem
        //        {
        //            Entity = newItem,
        //            State = Microsoft.EntityFrameworkCore.EntityState.Modified
        //        });
        //    }
        //    return this.CommitBatch(list) > 0;
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="folderId"></param>
        /// <param name="superPath"></param>
        /// <returns></returns>
        public bool Move(string group, string folderId, string superPath)
        {
            var targetSuper = this.CurrentDbContext.Folder.SingleOrDefault(f => f.Group == group && f.Path == superPath);

            var folder = this.CurrentDbContext.Folder.SingleOrDefault(f => f.Group == group && f.FolderId == folderId);

            var oldPath = folder.Path;
            var newPath = $"{superPath}{folder.FolderName}/";

            folder.SuperId = targetSuper.FolderId;
            folder.Path = newPath;
            folder.UpdateTime = DateTime.Now;

            var children = this.CurrentDbContext.Folder.Where(f => f.Group == group && f.Path != oldPath && f.Path.StartsWith(oldPath)).ToArray();
            var files = this.CurrentDbContext.File.Where(f => f.Group == group && f.Path.StartsWith(oldPath)).ToArray();
            List<BatchOperationItem> list = [];
            list.Add(new BatchOperationItem
            {
                Entity = folder,
                State = Microsoft.EntityFrameworkCore.EntityState.Modified
            });
            foreach (var item in children)
            {
                item.Path = item.Path.Replace(oldPath, newPath);
                item.UpdateTime = DateTime.Now;
                list.Add(new BatchOperationItem
                {
                    Entity = item,
                    State = Microsoft.EntityFrameworkCore.EntityState.Modified
                });
            }
            foreach(var f in files)
            {
                f.Path = f.Path.Replace(oldPath, newPath);
                f.UpdateTime = DateTime.Now;
                list.Add(new BatchOperationItem
                {
                    Entity = f,
                    State = Microsoft.EntityFrameworkCore.EntityState.Modified
                });
            }
            return this.CommitBatch(list) > 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public bool Remove(string group, string path)
        {
            var list = this.CurrentDbContext.Folder.Where(f => f.Group == @group && f.Path.StartsWith(path)).ToArray();
            int len = list.Length;
            if (len <= 0) return false;
            return this.Delete(list) >= len;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public bool Rename(string group, string path, string folderName)
        {
            var folders = this.CurrentDbContext.Folder.Where(f => f.Group == group && f.Path.StartsWith(path)).ToArray();
            var folder = folders.SingleOrDefault(f => f.Path == path);
            var super = this.CurrentDbContext.Folder.SingleOrDefault(f => f.Group == group && f.FolderId == folder.SuperId);
            var oldPath = folder.Path;
            var newPath = $"{super.Path}{folderName}/";
            folder.FolderName = folderName;

            List<BatchOperationItem> items = new();
            folders.ForEach(f =>
            {
                f.Path = f.Path.Replace(oldPath, newPath);
                f.UpdateTime = DateTime.Now;
                items.Add(new BatchOperationItem
                {
                    Entity = f,
                    State = Microsoft.EntityFrameworkCore.EntityState.Modified
                });
            });

            var files = this.CurrentDbContext.File.Where(f => f.Group == group && f.Path.StartsWith(path)).ToArray();
            files.ForEach(f =>
            {
                f.Path = f.Path.Replace(oldPath, newPath);
                f.UpdateTime = DateTime.Now;
                items.Add(new BatchOperationItem
                {
                    Entity = f,
                    State = Microsoft.EntityFrameworkCore.EntityState.Modified
                });
            });
            return this.CommitBatch(items) > 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderObjects"></param>
        /// <returns></returns>
        public bool Create(string group, string folderId, string folderName, string path, string superId)
        {
            var folder = new Folder()
            {
                FolderId = folderId,
                Path = path,
                FolderName = folderName,
                Group = group,
                Ordinal = 0,
                SuperId = superId,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            };
            return this.Insert(folder) > 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public bool PathExists(string group, string path)
        {
            return this.CurrentDbContext.Folder.Any(f => f.Group == group && f.Path == path);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderId"></param>
        /// <returns></returns>
        public IEnumerable<FileData> GetFiles(string folderId)
        {
            var folder = this.CurrentDbContext.Folder.SingleOrDefault(f => f.FolderId == folderId);
            if (folder == null) return [];
            return GetFiles(folder.Group, folder.Path);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public IEnumerable<FileData> GetFiles(string group, string path)
        {
            var files = (from f in this.CurrentDbContext.File
                         where f.Group == @group && f.Path == path
                         select new FileData
                         {
                             FileId = f.FileId,
                             FileName = f.FileName,
                             Group = f.Group,
                             Path = f.Path,
                             ContentLength = f.ContentLength,
                             ContentType = f.MimeType,
                             CreateTime = f.CreateTime,
                             UpdateTime = f.UpdateTime
                         }).ToArray();
            return files;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderId"></param>
        /// <returns></returns>
        public FolderObject GetFolder(string folderId)
        {
            var folder = this.CurrentDbContext.Folder.SingleOrDefault(f => f.FolderId == folderId);
            if (folder == null)
                return null;
            return CreateMapping().Compile()(folder);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public FolderObject GetFolder(string group, string path)
        {
            var folder = this.CurrentDbContext.Folder.SingleOrDefault(f => f.Group == group && f.Path == path);
            if (folder == null)
                return null;
            return CreateMapping().Compile()(folder);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="superId"></param>
        /// <returns></returns>
        public IEnumerable<FolderObject> GetFolders(string superId)
        {
            var list = (from folder in this.CurrentDbContext.Folder where folder.SuperId == superId select new FolderObject
            {
                FolderId = folder.FolderId,
                FolderName = folder.FolderName,
                Group = folder.Group,
                Path = folder.Path,
                SuperId = folder.SuperId,
                Ordinal = folder.Ordinal,
                CreateTime = folder.CreateTime,
                UpdateTime = folder.UpdateTime,
            }).ToArray();
            return list;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public IEnumerable<FolderObject> GetFolders(string group, string path)
        {
            var super = GetFolder(group, path);
            return GetFolders(super.FolderId);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public IEnumerable<FolderObject> GetAllFolders(string group, string path)
        {
            var list = this.CurrentDbContext.Folder.Where(f => f.Group == @group && f.Path.StartsWith(path)).Select(this.CreateMapping()).ToArray();
            return list;
        }

        //private FolderObject MappintVo(Folder folder)
        //{
        //    if (folder == null) return null;
        //    return new FolderObject
        //    {
        //        FolderId = folder.FolderId,
        //        FolderName = folder.FolderName,
        //        Group = folder.Group,
        //        Path = folder.Path,
        //        SuperId = folder.SuperId,
        //        Ordinal = folder.Ordinal,
        //        CreateTime = folder.CreateTime,
        //        UpdateTime = folder.UpdateTime,
        //        Files = (from f in this.CurrentDbContext.File
        //                 where f.Group == folder.Group && f.Path == folder.Path
        //                 select new FileData
        //                 {
        //                     FileId = f.FileId,
        //                     FileName = f.FileName,
        //                     ContentType = f.MimeType,
        //                     Group = f.Group,
        //                     Path = f.Path,
        //                     CreateTime = f.CreateTime,
        //                     UpdateTime = f.UpdateTime
        //                 }).ToArray()
        //    };
        //}
    }
}
